package org.lex.swing.widgets;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JWindow;
import javax.swing.SwingConstants;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.border.EtchedBorder;

class NotifyWindow extends JWindow {
	private static final int MIN_WIDTH = 210;
	private static final int MIN_HEIGHT = 50;
	private static final int ICON_WIDTH = 50;
	// =========================================
	private static final int MOVE_TIMER_STEP = 1;
	private static final int MOVE_TIMER_DELAY = 20;
	private static final int LAST_TIME = 3000;
	// =========================================
	private static final Toolkit dt;
	private static final GraphicsConfiguration gc;

	static {
		dt = Toolkit.getDefaultToolkit();
		gc = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
	}
	// ======================================
	private JPanel pane = null;
	private JLabel messageLabel = null;
	private Dimension size = null;
	private Insets insets = null;

	public NotifyWindow(String message) {
		super((Frame) null);
		initialize();
		this.setMessage(message);
	}

	public NotifyWindow(String message, JNotifyWindow.Type messageType) {
		this(message);
		this.setMessageType(messageType);
	}

	void popup() {
		size = dt.getScreenSize();
		insets = dt.getScreenInsets(gc);
		this.setLocation(size.width - insets.right - this.getWidth() - 1, size.height - insets.bottom);
		new MoveTimer(this).start();
		this.setVisible(true);
	}

	void setMessage(String message) {
		this.getMessageLabel().setText(message);
		Dimension ps = this.getMessageLabel().getPreferredSize();
		if (ps.width > MIN_WIDTH)
			this.setSize(ps.width + ICON_WIDTH, 0);
		else
			this.setSize(MIN_WIDTH, 0);
	}

	void setMessageType(JNotifyWindow.Type messageType) {
		String key = messageType.getKey();
		this.getMessageLabel().setIcon(UIManager.getIcon(key));
	}

	private void initialize() {
		this.setContentPane(getPane());
		this.setAlwaysOnTop(true);
	}

	private JPanel getPane() {
		if (pane == null) {
			pane = new JPanel();
			pane.setLayout(new BorderLayout());
			pane.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED));
			pane.add(getMessageLabel(), BorderLayout.CENTER);
			pane.add(Box.createHorizontalStrut(6), BorderLayout.WEST);
		}
		return pane;
	}

	private JLabel getMessageLabel() {
		if (null == this.messageLabel) {
			messageLabel = new JLabel();
			messageLabel.setHorizontalAlignment(SwingConstants.LEADING);
			messageLabel.setDoubleBuffered(true);
			messageLabel.setHorizontalTextPosition(SwingConstants.TRAILING);
			messageLabel.addMouseListener(new MouseAdapter() {
				public void mouseClicked(MouseEvent e) {
					dispose();
				}
			});
		}
		return this.messageLabel;
	}

	static class MoveTimer extends Timer implements ActionListener {
		private Window window = null;
		private int step = MOVE_TIMER_STEP;
		private boolean sign = false;

		public MoveTimer(Window root) {
			super(MOVE_TIMER_DELAY, null);
			this.window = root;
			this.addActionListener(this);
			this.setInitialDelay(100);
		}

		public void actionPerformed(ActionEvent e) {
			Dimension cs = window.getSize();
			if (false == sign && cs.height >= MIN_HEIGHT) {
				sign = true;
				this.stop();
				new DelayTimer(this).start();
				step = -step;
				return;
			}
			if (true == sign && cs.height <= MOVE_TIMER_STEP) {
				this.stop();
				window.dispose();
				window = null;
				return;
			}
			Point loc = window.getLocation();
			loc.y -= step;
			window.setSize(cs.width, cs.height + step);
			window.setLocation(loc);

		}
	}

	static class DelayTimer extends Timer implements ActionListener {
		private Timer moveTimer = null;

		public DelayTimer(Timer moveTimer) {
			super(LAST_TIME, null);
			this.setInitialDelay(LAST_TIME);
			this.addActionListener(this);
			this.moveTimer = moveTimer;
		}

		public void actionPerformed(ActionEvent e) {
			moveTimer.start();
			this.stop();
			moveTimer = null;
		}
	}
}
